﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace RPCServer
{
    public static class CommolOption
    {
        public static string[] GetAllFilePath(string directory, string suffix)
        {
            List<string> paths = new();
            foreach (var item in Directory.EnumerateFiles(directory, '*' + suffix))
            {
                paths.Add(item);
                Console.WriteLine(item);
            }
            return paths.ToArray();
        }

        public static string GetFilePathName(string filePath)
        {
            return Path.GetFileNameWithoutExtension(filePath).ToString();
        }

        public static void Switch<T>(T a, T b)
        {
            T t = a;
            a = b;
            b = t;
        }

        public static void Switch<T>(ref T a, ref T b)
        {
            T t = a;
            a = b;
            b = t;
        }

        public static void Switch<T, V>(V source, int x, int y) where V : IList<T>
        {
            T t = source[x];
            source[x] = source[y];
            source[y] = t;
        }

        public static void Switch<T, V>(V sourceX, int x, V sourceY, int y) where V : IList<T>
        {
            T t = sourceX[x];
            sourceX[x] = sourceY[y];
            sourceY[y] = t;
        }

        public static void SwitchWhen<T>(ref T a, ref T b, Func<T, T, bool> compare)
        {
            if (compare.Invoke(a, b))
            {
                Switch<T>(ref a, ref b);
            }
        }

        public static string ShowAssemblyTypes(Assembly asmb)
        {
            StringBuilder sb = new();

            foreach (Type type in asmb.GetTypes())
            {
                sb.AppendFormat($"[TypeName]: {type.Name} [BaseType]: {type.BaseType} \n");
            }
            return sb.ToString();
        }

        public static string ShowAssemblyTypes(Assembly asmb, Type baseType)
        {
            StringBuilder sb = new();

            foreach (Type type in asmb.GetTypes())
            {
                if (baseType == type.BaseType)
                    sb.AppendFormat($"[TypeName]: {type.Name} [BaseType]: {type.BaseType} \n");
            }
            return sb.ToString();
        }

        public static MethodInfo GetMethod(Type type, string name)
        {
            foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.CreateInstance))
            {
                if (method.Name == name)
                    return method;
            }
            return default;
        }

        public static string ShowTypeMethods(Type type)
        {
            StringBuilder sb = new();

            foreach (var method in type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.CreateInstance))
            {
                sb.AppendFormat($"[Method] {method.Name} [ReturnType] {method.ReturnType} [IsPrivate] {method.IsPrivate} [IsStatic] {method.IsStatic}\n");
            }
            return sb.ToString();
        }

        public static T GetAttribute<T>(Type type) where T : Attribute
        {
            foreach (var ab in type.GetCustomAttributes(false))
            {
                if (ab.GetType() is T t)
                    return t;
            }
            return default;
        }

        public static Type[] GetTypesWhitAttribute<T>(this Assembly asmb) where T : Attribute
        {
            List<Type> types = new();
            Type baseAb = typeof(T);
            foreach (Type type in asmb.GetTypes())
            {
                foreach (var ab in type.GetCustomAttributes(false))
                {
                    if (ab.GetType() == baseAb)
                    {
                        types.Add(type);
                    }
                }
            }

            return types.ToArray();
        }

        public static Type[] GetAttributeTypes<T>(Assembly asmb) where T : Attribute
        {
            List<Type> types = new();
            Type baseAb = typeof(T);
            foreach (Type type in asmb.GetTypes())
            {
                foreach (var ab in type.GetCustomAttributes(false))
                {
                    if (ab.GetType() == baseAb)
                    {
                        types.Add(type);
                    }
                }
            }

            return types.ToArray();
        }

        public static MethodInfo GetAnyMethod(Type type, string methodName)
        {
            return type.GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
        }

        public static T CreateDelegate<T>(object obj, MethodInfo method) where T : Delegate
        {
            return method.CreateDelegate(typeof(T), obj) as T;
        }

        public static bool TryCreateDelegateWithInstance<T>(object obj, string methodName, out T t) where T : Delegate
        {
            MethodInfo method = GetAnyMethod(obj.GetType(), methodName);
            t = null;

            if (method == null || method.IsStatic)
                return false;

            t = method.CreateDelegate(typeof(T), obj) as T;
            return true;
        }

        public static bool TryCreateDelegate<T>(Type type, string methodName, out T t) where T : Delegate
        {
            MethodInfo method = GetMethod(type, methodName);
            t = null;

            if (method == null || !method.IsStatic)
                return false;

            t = method.CreateDelegate(typeof(T)) as T;
            return true;
        }


        public static T GetFieldValue<T>(object obj, string name)
        {
            Type type = obj.GetType();
            return (T)type.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).GetValue(obj);
        }

        public static void SetFieldValue<T>(object obj, string name, T value)
        {
            Type type = obj.GetType();
            type.GetField(name, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance).SetValue(obj,value);
        }


        public static void ShowBytes(byte[] value)
        {
            foreach (var item in value)
            {
                Console.Write(item);
            }
        }
    }
}

